﻿#pragma once
#include "crypto/FAQBaseBlockProcessAlgorithm.h"
#include "crypto/algorithms/ialgorithm/FAQAlgorithm.h"
#include "crypto/algorithms/ialgorithm/FAQKeyAlgorithm.h"
#include "crypto/keys/FAQKey.h"

namespace yzrilyzr_crypto{
	ECLASS(GHash, public FAQBaseBlockProcessAlgorithm, public FAQKeyAlgorithm){
	private:
	static constexpr int BLOCK_SIZE=16;
	static constexpr int64_t REDUCTION_POLYNOMIAL=0xE100000000000000L;
	yzrilyzr_array::ByteArray H;  // 子密钥H
	yzrilyzr_array::ByteArray Y;  // 当前状态
	yzrilyzr_util::MemoryFIFOBuffer<int8_t> aadBuffer;
	bool aadProcessed=false;
	public:
	~GHash()=default;
	GHash();
	void reset()override;

	protected:
	yzrilyzr_array::ByteArray processFinalBlock(const yzrilyzr_array::ByteArray & incompleteBlock)override;

	public:
	void processBlock(const yzrilyzr_array::ByteArray & block)override;
	yzrilyzr_lang::String getAlgorithmName()const override;
	std::shared_ptr<FAQAlgorithm> newInstance()const override;
	void setKey(const FAQKey & key)override;
	u_index getBlockSize()const override;
	void updateAAD(const yzrilyzr_array::ByteArray & input);
	void updateAAD(const yzrilyzr_array::ByteArray & input, u_index offset, u_index length);
	private:
	void mProcessBlock(const yzrilyzr_array::ByteArray & block);
	/**
	 * GF(2^128)乘法运算 Y = Y • H
	 * 使用Russian peasant算法
	 */
	void multiplyH();
	static int64_t bytesToLong(const yzrilyzr_array::ByteArray & bytes, u_index offset);
	static void longToBytes(int64_t value, const yzrilyzr_array::ByteArray & bytes, u_index offset);
	public:
	void doFinalAAD();
	};
}